package com.miui.cordova;

import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaInterface;
import org.apache.cordova.CordovaWebView;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.Arrays;
//import java.util.concurrent.ExecutorService;
//import java.util.concurrent.Executors;
//import java.util.Properties;
import java.io.IOException;

import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.app.Application;
import android.view.Window;
import android.content.Context;
import android.os.Process;
import android.os.Build;
import android.util.Log;
import android.text.TextUtils;

import com.xiaomi.channel.commonutils.logger.LoggerInterface;
import com.xiaomi.mipush.sdk.Constants;
import com.xiaomi.mipush.sdk.Logger;
import com.xiaomi.mipush.sdk.MiPushClient;
//import com.xiaomi.mipush.sdk.MiPushMessage;
import com.xiaomi.market.sdk.XiaomiUpdateAgent;

import com.xiaomi.mistatistic.sdk.MiStatInterface;

import com.miui.cordova.BuildProperties;

public class MiServicePlugin extends CordovaPlugin {

    // 此TAG在adb logcat中检索自己所需要的信息， 只需在命令行终端输入 adb logcat | grep
    // com.xiaomi.mipushdemo
    public static final String TAG = "com.xiaomi.miServices";

    /**
     * @see http://dev.xiaomi.com/doc/?p=544#d5e91
     */
    private final static List<String> methodList = Arrays.asList(
            "getMiuiVersion",
            "updateAgent",
            "immersiveMode",
            //miStats
            "miStatsInit",
            "setUploadPolicy",
            "recordPageStart",
            "recordPageEnd",
            "recordCountEvent",
            "recordCalculateEvent",
            "recordStringPropertyEvent",
            "recordNumericPropertyEvent",
            "triggerUploadManually",
            "getDeviceID",
            //mipush
            "registerPush", "unregisterPush", "setAlias", "unsetAlias", "subscribe", "unsubscribe",
            "pausePush", "resumePush", "setAcceptTime", "getAllAlias", "getAllTopic", "reportMessageClicked", "onReceiveMessage");

    //private ExecutorService threadPool = Executors.newFixedThreadPool(1);
    private static MiServicePlugin instance;
    //private static MPHandler handler = null;

    public MiServicePlugin() {
        instance = this;
    }

    @Override
    public void initialize(CordovaInterface cordova, CordovaWebView webView) {

        // initial
        super.initialize(cordova, webView);

        //miui6沉浸
        //immersiveMode();
    }

    /**
     * 接收推送通知消息
     *
     * @param message
     */
    static void transmitPush(String message) {
        if (instance == null) {
            Log.w(TAG, "transmitPush: instance is null");
            return;
        }
        //待处理?
        String js = String.format("window.miService.mipush.onReceiveMessage('%s');", message);
        try {
            instance.webView.sendJavascript(js);
        } catch (NullPointerException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 返回消息通知
     *
     * @param message
     */
    static void transmitResult(String message) {
        if (instance == null) {
            Log.w(TAG, "transmitResult: instance is null");
            return;
        }

        String js = String.format("window.miService.mipush.onCommandResult('%s');", message);
        try {
            instance.webView.sendJavascript(js);
        } catch (NullPointerException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public boolean execute(final String action, final JSONArray data, final CallbackContext callbackContext) throws JSONException {
        if (!methodList.contains(action)) {
            Log.w(TAG, "method[" + action + "] not in list!");
            callbackContext.error("method[" + action + "] not in:" + methodList.toString());
            return false;
        }
        if (action.equals("immersiveMode")) {
            cordova.getActivity().runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    try {
                        boolean bool = immersiveMode(data.getString(0));
                        if (bool) {
                            callbackContext.success(1);
                        } else {
                            callbackContext.error(0);
                        }

                    } catch (Exception e) {
                        Log.e(TAG, e.toString());
                        callbackContext.error(e.getMessage());
                    }
                }
            });
        } else {
            final Context context = cordova.getActivity().getApplicationContext();
            cordova.getThreadPool().execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        Method method = MiServicePlugin.class.getDeclaredMethod(action, JSONArray.class, CallbackContext.class, Context.class);
                        method.invoke(MiServicePlugin.this, data, callbackContext, context);
                    } catch (Exception e) {
                        Log.e(TAG, e.toString());
                    }
                }
            });
        }
        return true;
    }

    /**
     * miui6沉浸
     *
     * @param data
     * @param callbackContext
     * @param mainActivity
     */
    private boolean immersiveMode(String mode) {
        if (isMiuiVersion("V6")) {
            try {
                Window window = cordova.getActivity().getWindow();

                Class clazz = window.getClass();
                int tranceFlag = 0;
                int darkModeFlag = 0;
                Class layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");

                Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_TRANSPARENT");
                tranceFlag = field.getInt(layoutParams);

                field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");
                darkModeFlag = field.getInt(layoutParams);

                Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class);
                extraFlagField.setAccessible(true);
                if (mode.equals("trance")) {
                    // 只需要状态栏透明
                    extraFlagField.invoke(window, tranceFlag, tranceFlag);
                } else if (mode.equals("dark")) {// 等于关闭
                    // 清除黑色字体
                    extraFlagField.invoke(window, 0, darkModeFlag);
                } else {
                    // 状态栏透明且黑色字体
                    extraFlagField.invoke(window, tranceFlag | darkModeFlag, tranceFlag | darkModeFlag);
                }
                return true;
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return false;
    }

    /**
     * 判断miui的信息 default: ro.miui.ui.version.name
     *
     * @param value
     */
    private static boolean isMiuiVersion(String value) {
        return isMiuiVersion(value, "ro.miui.ui.version.name");
    }

    /**
     * 判断miui的信息
     *
     * @param value
     * @param name
     */
    private static boolean isMiuiVersion(String value, String name) {
        try {
            return getMiuiVersion(name).equalsIgnoreCase(value);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 得到miui的信息
     *
     * @param name
     */
    private static String getMiuiVersion(String name) {
        if (!Build.MANUFACTURER.equalsIgnoreCase("Xiaomi") || TextUtils.isEmpty(name)) {
            return "";
        }
        try {
            final BuildProperties prop = BuildProperties.newInstance();
            return prop.getProperty(name);
        } catch (final IOException e) {
            e.printStackTrace();
            return "";
        }
    }

    /**
     * 需要init?
     *
     * @return
     */
    private boolean shouldInit() {
        Activity mainActivity = cordova.getActivity();
        ActivityManager am = ((ActivityManager) mainActivity.getSystemService(Context.ACTIVITY_SERVICE));
        List<RunningAppProcessInfo> processInfos = am.getRunningAppProcesses();
        String mainProcessName = mainActivity.getPackageName();
        int myPid = Process.myPid();
        for (RunningAppProcessInfo info : processInfos) {
            if (info.pid == myPid && mainProcessName.equals(info.processName)) {
                return true;
            }
        }
        return false;
    }

    /**
     * MiPushClient handler
     *
     * @return
     */
    //public static MPHandler getHandler() {
    //	return handler;
    //}
    // **************************************************************
    /**
     * 得到miui的版本 cordova
     *
     * @param data
     * @param callbackContext
     * @param mainActivity
     */
    void getMiuiVersion(JSONArray data, CallbackContext callbackContext, Context context) {
        try {
            //[ro.miui.ui.version.name, ro.miui.ui.version.code, ro.miui.internal.storage]
            String name = data.getString(0);
            if (name.equalsIgnoreCase("code")) {
                name = "ro.miui.ui.version.code";
            } else if (name.equalsIgnoreCase("storage")) {
                name = "ro.miui.internal.storage";
            } else {
                name = "ro.miui.ui.version.name";
            }
            callbackContext.success(getMiuiVersion(name));
        } catch (JSONException e) {
            e.printStackTrace();
            callbackContext.error(e.getMessage());
        }

    }

    // **************************************************************
    /**
     * 检查更新 cordova
     *
     * @param data
     * @param callbackContext
     * @param mainActivity
     */
    void updateAgent(JSONArray data, CallbackContext callbackContext, Context context) {
        boolean onlyWifi = false;
        try {
            //update sdk
            onlyWifi = data.getString(0).equalsIgnoreCase("true");
        } catch (JSONException e) {
        }

        XiaomiUpdateAgent.setCheckUpdateOnlyWifi(onlyWifi);
        XiaomiUpdateAgent.update(cordova.getActivity());
        callbackContext.success();
    }

    // **************************************************************
    /**
     * 初始化统计
     *
     * @param data
     * @param callbackContext
     * @param mainActivity
     */
    void miStatsInit(JSONArray data, CallbackContext callbackContext, Context context) {
        String APP_ID = null;
        String APP_KEY = null;
        String CHANNEL = null;

        try {
            JSONObject args = data.getJSONObject(0);
            APP_ID = args.getString("appID");
            APP_KEY = args.getString("appKey");
            CHANNEL = args.getString("channel");
        } catch (JSONException e) {
            e.printStackTrace();
        }

        if (TextUtils.isEmpty(APP_ID) || TextUtils.isEmpty(APP_KEY)) {
            callbackContext.error("APP Error: APP_ID[" + APP_ID + "] or APP_KEY[" + APP_KEY + "] isEmpty.");
            return;
        }

        if (TextUtils.isEmpty(CHANNEL)) {
            CHANNEL = "stats";
        }

        MiStatInterface.initialize(context, APP_ID, APP_KEY, CHANNEL);
        callbackContext.success();

    }

    /**
     * 设置上报策略接口
     *
     * @param data
     * @param callbackContext
     * @param mainActivity
     */
    void setUploadPolicy(JSONArray data, CallbackContext callbackContext, Context context) {

        /**
         * public static final int UPLOAD_POLICY_REALTIME = 0; public static
         * final int UPLOAD_POLICY_WIFI_ONLY = 1; public static final int
         * UPLOAD_POLICY_BATCH = 2; public static final int
         * UPLOAD_POLICY_WHILE_INITIALIZE = 3; public static final int
         * UPLOAD_POLICY_INTERVAL = 4; public static final int
         * UPLOAD_POLICY_DEVELOPMENT = 5;
         */
        try {
            JSONObject args = data.getJSONObject(0);
            MiStatInterface.setUploadPolicy(args.getInt("policy"), args.getLong("interval"));
            callbackContext.success();
        } catch (JSONException e) {
            e.printStackTrace();
            callbackContext.error(e.getMessage());
        }

    }

    /**
     * 记录界面进入事件，建议放在Activity或Fragment的onResume方法中调用。
     *
     * @param data
     * @param callbackContext
     * @param mainActivity
     */
    void recordPageStart(JSONArray data, CallbackContext callbackContext, Context context) {
        String pageName = null;
        try {
            pageName = data.getString(0);
        } catch (JSONException e) {
            e.printStackTrace();
            pageName = TAG;
        }
        MiStatInterface.recordPageStart(cordova.getActivity(), pageName);
        callbackContext.success();
    }

    /**
     * 记录当前页面访问结束。
     *
     * @param data
     * @param callbackContext
     * @param mainActivity
     */
    void recordPageEnd(JSONArray data, CallbackContext callbackContext, Context context) {
        MiStatInterface.recordPageEnd();
        callbackContext.success();
    }

    /**
     * 记录自定义计数事件。
     *
     * @param data
     * @param callbackContext
     * @param mainActivity
     */
    void recordCountEvent(JSONArray data, CallbackContext callbackContext, Context context) {
        try {
            JSONObject args = data.getJSONObject(0);
            MiStatInterface.recordCountEvent(args.getString("category"), args.getString("key"));
            callbackContext.success();
        } catch (JSONException e) {
            e.printStackTrace();
            callbackContext.error(e.getMessage());
        }
    }

    /**
     * 记录自定义计算事件。
     *
     * @param data
     * @param callbackContext
     * @param mainActivity
     */
    void recordCalculateEvent(JSONArray data, CallbackContext callbackContext, Context context) {
        try {
            JSONObject args = data.getJSONObject(0);
            MiStatInterface.recordCalculateEvent(args.getString("category"), args.getString("key"), args.getLong("value"));
            callbackContext.success();
        } catch (JSONException e) {
            e.printStackTrace();
            callbackContext.error(e.getMessage());
        }
    }

    /**
     * 记录自定义字符串属性事件。
     *
     * @param data
     * @param callbackContext
     * @param mainActivity
     */
    void recordStringPropertyEvent(JSONArray data, CallbackContext callbackContext, Context context) {
        try {
            JSONObject args = data.getJSONObject(0);
            MiStatInterface.recordStringPropertyEvent(args.getString("category"), args.getString("key"), args.getString("value"));
            callbackContext.success();
        } catch (JSONException e) {
            e.printStackTrace();
            callbackContext.error(e.getMessage());
        }
    }

    /**
     * 记录自定义数值属性事件。
     *
     * @param data
     * @param callbackContext
     * @param mainActivity
     */
    void recordNumericPropertyEvent(JSONArray data, CallbackContext callbackContext, Context context) {
        try {
            JSONObject args = data.getJSONObject(0);
            MiStatInterface.recordNumericPropertyEvent(args.getString("category"), args.getString("key"), args.getLong("value"));
            callbackContext.success();
        } catch (JSONException e) {
            e.printStackTrace();
            callbackContext.error(e.getMessage());
        }
    }

    /**
     * 手动触发上报，该调用仅会在当上报策略设置为UPLOAD_POLICY_DEVELOPMENT时起作用。
     *
     * @param data
     * @param callbackContext
     * @param mainActivity
     */
    void triggerUploadManually(JSONArray data, CallbackContext callbackContext, Context context) {
        MiStatInterface.triggerUploadManually();
        callbackContext.success();
    }

    /**
     * 获取设备标示。在接入SDK时, 通过此方法获取设备标示，添加到测试设备中，就可以在测试数据列表中看到该设备上报的统计数据。
     *
     * @param data
     * @param callbackContext
     * @param mainActivity
     */
    void getDeviceID(JSONArray data, CallbackContext callbackContext, Context context) {
        String deviceID = MiStatInterface.getDeviceID(context);
        callbackContext.success(deviceID);
    }

    // **************************************************************
    /**
     * 注册push服务
     *
     * @param data
     * @param callbackContext
     * @param mainActivity
     */
    void registerPush(JSONArray data, CallbackContext callbackContext, Context context) {
        // user your appid the key.
        String APP_ID = null;
        // user your appid the key.
        String APP_KEY = null;
        //if (handler == null)
        //	handler = new MPHandler(context);

        try {
            APP_ID = data.getString(0);
            APP_KEY = data.getString(1);
        } catch (JSONException e) {
            e.printStackTrace();
            APP_ID = null;
            APP_KEY = null;
        }

        // 注册push服务，注册成功后会向DemoMessageReceiver发送广播
        // 可以从DemoMessageReceiver的onCommandResult方法中MiPushCommandMessage对象参数中获取注册信息
        if (TextUtils.isEmpty(APP_ID) || TextUtils.isEmpty(APP_KEY)) {
            /*
             int appResId = context.getResources().getIdentifier("mi_app_id", "string", context.getPackageName());
             int appResKey = context.getResources().getIdentifier("mi_app_key", "string", context.getPackageName());

             APP_ID = context.getString(appResId);
             APP_KEY = context.getString(appResKey);
             */
            callbackContext.error("APP Error: APP_ID[" + APP_ID + "] or APP_KEY[" + APP_KEY + "] isEmpty.");
            return;
        }

        Activity mainActivity = cordova.getActivity();
        if (shouldInit()) {
            MiPushClient.registerPush(mainActivity, APP_ID, APP_KEY);
            Log.d(TAG, "shouldInit true, ID:" + APP_ID + " KEY:" + APP_KEY);
            callbackContext.success();
        } else {
            Log.w(TAG, "shouldInit false");
            callbackContext.error("shouldInit is false");
        }
        // 打开Log
        LoggerInterface newLogger = new LoggerInterface() {

            @Override
            public void setTag(String tag) {
                // ignore
            }

            @Override
            public void log(String content, Throwable t) {
                Log.d(TAG, content, t);
            }

            @Override
            public void log(String content) {
                Log.d(TAG, content);
            }
        };
        Logger.setLogger(mainActivity, newLogger);

    }

    /**
     * 取消注册,关闭推送
     *
     * @param data
     * @param callbackContext
     * @param mainActivity
     */
    void unregisterPush(JSONArray data, CallbackContext callbackContext, Context context) {
        try {
            MiPushClient.unregisterPush(context);
            Logger.disablePushFileLog(context);
            callbackContext.success();
        } catch (Exception e) {
            e.printStackTrace();
            callbackContext.error(e.getMessage());
        }

    }

    // /////////////////////////////////////////////////
    /**
     * 设置别名, 针对设备
     *
     * @param data
     * @param callbackContext
     * @param mainActivity
     */
    void setAlias(JSONArray data, CallbackContext callbackContext, Context context) {
        try {
            String alias = data.getString(0);
            MiPushClient.setAlias(context, alias, null);
            callbackContext.success();
        } catch (JSONException e) {
            e.printStackTrace();
            callbackContext.error(e.getMessage());
        }
    }

    /**
     * 取消别名
     *
     * @param data
     * @param callbackContext
     * @param mainActivity
     */
    void unsetAlias(JSONArray data, CallbackContext callbackContext, Context context) {
        try {
            String alias = data.getString(0);
            MiPushClient.unsetAlias(context, alias, null);
            callbackContext.success();
        } catch (JSONException e) {
            e.printStackTrace();
            callbackContext.error(e.getMessage());
        }

    }

    /**
     * 为某个用户设置订阅主题；根据用户订阅的不同主题，开发者可以根据订阅的主题实现分组群发。
     *
     * @param data
     * @param callbackContext
     * @param context
     */
    void subscribe(JSONArray data, CallbackContext callbackContext, Context context) {
        try {
            String topic = data.getString(0);// 某个用户设置订阅的主题
            MiPushClient.subscribe(context, topic, null);
            callbackContext.success();
        } catch (JSONException e) {
            e.printStackTrace();
            callbackContext.error(e.getMessage());
        }
    }

    /**
     * 为某个用户取消某个订阅主题。
     *
     * @param data
     * @param callbackContext
     * @param context
     */
    void unsubscribe(JSONArray data, CallbackContext callbackContext, Context context) {
        try {
            String topic = data.getString(0);
            MiPushClient.unsubscribe(context, topic, null);
            callbackContext.success();
        } catch (JSONException e) {
            e.printStackTrace();
            callbackContext.error(e.getMessage());
        }
    }

    /**
     * 设置接收MiPush服务推送的时段，不在该时段的推送消息会被缓存起来，到了合适的时段再向app推送原先被缓存的消息。
     * 这里采用24小时制，如果开始时间早于结束时间，则这个时段落在一天内；否则，这个时间将会跨越凌晨0点。
     * 如果时间设置为0:00-0:00，就是暂停push推送服务，也可以直接调用pausePush()方法，其本质相同
     * 如果时间设置为0:00-23:59，就是恢复push推送服务，即全天接收push推送消息，也可以直接调用resumePush()方法，其本质相同
     *
     * @param data
     * @param callbackContext
     * @param context
     */
    void setAcceptTime(JSONArray data, CallbackContext callbackContext, Context context) {
        /**
         * @param startHour 接收时段开始时间的小时
         * @param startMin 接收时段开始时间的分钟
         * @param endHour 接收时段结束时间的小时
         * @param endMin 接收时段结束时间的分钟
         */
        try {
            int startHour = data.getInt(0);
            int startMin = data.getInt(1);
            int endHour = data.getInt(2);
            int endMin = data.getInt(3);
            MiPushClient.setAcceptTime(context, startHour, startMin, endHour, endMin, null);
            callbackContext.success();
        } catch (JSONException e) {
            e.printStackTrace();
            callbackContext.error(e.getMessage());
        }
    }

    /**
     * 暂停接收MiPush服务推送的消息，app在恢复MiPush推送服务之前，不接收任何推送消息
     *
     * @param data
     * @param callbackContext
     * @param context
     */
    void pausePush(JSONArray data, CallbackContext callbackContext, Context context) {

        MiPushClient.pausePush(context, null);
        callbackContext.success();

    }

    /**
     * 恢复接收MiPush服务推送的消息
     *
     * @param data
     * @param callbackContext
     * @param context
     */
    void resumePush(JSONArray data, CallbackContext callbackContext, Context context) {

        MiPushClient.resumePush(context, null);
        callbackContext.success();

    }

    /**
     * 获取客户端所有设置的别名。
     *
     * @param data
     * @param callbackContext
     * @param context
     */
    void getAllAlias(JSONArray data, CallbackContext callbackContext, Context context) throws JSONException {
        List<String> allAlias = MiPushClient.getAllAlias(context);
        try {
            callbackContext.success(new JSONArray(allAlias).toString());
        } catch (Exception e) {
            e.printStackTrace();
            callbackContext.error(e.getMessage());
        }
    }

    /**
     * 获取客户端所有订阅的主题。
     *
     * @param data
     * @param callbackContext
     * @param context
     */
    void getAllTopic(JSONArray data, CallbackContext callbackContext, Context context) throws JSONException {
        List<String> allTopic = MiPushClient.getAllTopic(context);
        try {
            callbackContext.success(new JSONArray(allTopic).toString());
        } catch (Exception e) {
            e.printStackTrace();
            callbackContext.error(e.getMessage());
        }
    }

    /**
     * 上报点击的消息。
     *
     * @param data
     * @param callbackContext
     * @param context
     */
    void reportMessageClicked(JSONArray data, CallbackContext callbackContext, Context context) {

    }

    /**
     * 接收服务器推送的消息。
     *
     * @param data
     * @param callbackContext
     * @param context
     */
    void onReceiveMessage(JSONArray data, CallbackContext callbackContext, Context context) {

    }

}
